package light.mvc.service.workflow.impl;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.annotation.Resource;

import light.mvc.dao.BaseDaoI;
import light.mvc.model.sys.Tuser;
import light.mvc.model.workflow.TapproveInfo;
import light.mvc.model.workflow.Tfield;
import light.mvc.model.workflow.Tform;
import light.mvc.model.workflow.TformTemplate;
import light.mvc.pageModel.base.PageFilter;
import light.mvc.pageModel.sys.User;
import light.mvc.pageModel.workflow.ApproveInfo;
import light.mvc.pageModel.workflow.FieldPageModel;
import light.mvc.pageModel.workflow.Form;
import light.mvc.pageModel.workflow.FormTemplate;
import light.mvc.pageModel.workflow.TaskView;
import light.mvc.service.mail.MailService;
import light.mvc.service.workflow.FormServiceI;
import light.mvc.utils.LightmvcConstants;
import light.mvc.utils.MailAddress;

import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Service;

@Service
public class FormServiceImpl implements FormServiceI {
	private static Logger logger = Logger.getLogger(FormServiceImpl.class);
	@Resource
	private HibernateTemplate hibernateTemplate;
	@Autowired
	private BaseDaoI<Tform> formDao;
	@Autowired
	private BaseDaoI<Tuser> userDao;
	@Autowired
	private BaseDaoI<TformTemplate> formTemplateDao;
	@Autowired
	private BaseDaoI<TapproveInfo> approveInfoDao;
	@Autowired
	private ProcessEngine processEngine;
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

	@Override
	public List<FormTemplate> findAll() {
		List<FormTemplate> ul = new ArrayList<FormTemplate>();
		String hql = "from Tform";
		List<Tform> l = formDao.find(hql);
		for (Tform Tform : l) {
			FormTemplate formTemplate = new FormTemplate();
			BeanUtils.copyProperties(Tform, formTemplate);
			ul.add(formTemplate);
		}
		return ul;
	}

	@Override
	public List<FormTemplate> dataGrid(FormTemplate formTemplate, PageFilter ph) {
		List<FormTemplate> ul = new ArrayList<FormTemplate>();
		Map<String, Object> params = new HashMap<String, Object>();
		String hql = " from Tform t ";
		List<Tform> l = formDao.find(hql + orderHql(ph), params, ph.getPage(), ph.getRows());
		for (Tform t : l) {
			FormTemplate u = new FormTemplate();
			BeanUtils.copyProperties(t, u);
			ul.add(u);
		}
		return ul;
	}

	private String orderHql(PageFilter ph) {
		String orderString = "";
		if ((ph.getSort() != null) && (ph.getOrder() != null)) {
			orderString = " order by t." + ph.getSort() + " " + ph.getOrder();
		}
		return orderString;
	}

	@Override
	public void save(FormTemplate formTemplate) {
		Tform t = new Tform();
		BeanUtils.copyProperties(formTemplate, t);
		formDao.save(t);
	}

	@Override
	public void submit(Tform form, List<FieldPageModel> fields, String isProxy, String loginName, String name) throws Exception {
		ProcessInstance pi = saveFormAndStartProcess(form, fields, isProxy, name);

		finishFirstTaskAndSendEmail(form, pi);

		proxyApply(form, isProxy, loginName, name, pi);
	}

	/**
	 * @param form
	 * @param isProxy
	 * @param loginName
	 * @param name
	 * @param pi
	 * @throws Exception 
	 */
	private void proxyApply(Tform form, String isProxy, String loginName, String name, ProcessInstance pi) throws Exception {
		/**
		 * 如果是代申请
		 */
		if (isProxy != null && isProxy.equals("on")) {
			String taskId2 = processEngine.getTaskService().createTaskQuery().processInstanceId(pi.getId()).assignee(loginName).uniqueResult().getId();
			String executionIdProxy = processEngine.getTaskService().getTask(taskId2).getExecutionId();
			String startTime = (String) processEngine.getExecutionService().getVariable(executionIdProxy, LightmvcConstants.STAFF_STARTTIME);
			String endTime = (String) processEngine.getExecutionService().getVariable(executionIdProxy, LightmvcConstants.STAFF_ENDTIME);
			//发给考勤员
			String executionIdSubmit = processEngine.getTaskService().getTask(taskId2).getExecutionId();
			String content = createContentForSubmit(executionIdSubmit);
			MailService.sendMail(form.getTitle(), content, MailAddress.MONITOR_MAILBOX);
			processEngine.getTaskService().completeTask(taskId2); // 完成任务
			// 判断：如果本流程实例已执行完，表示本次是最后一个审批
			ProcessInstance piNew = processEngine.getExecutionService().findProcessInstanceById(pi.getId());
			if (piNew == null) {
				form.setStatus(Form.STATUS_APPROVED);
				form.setRegister(name);
				Tuser user = form.getApplicant();
				user.setStatus(Tuser.STATUS_HOLIDAY);
				userDao.update(user);
				formDao.save(form); // 保存表单
			}
		}
	}

	/**
	 * @param form
	 * @param pi
	 * @throws IOException 
	 */
	private void finishFirstTaskAndSendEmail(Tform form, ProcessInstance pi) throws Exception {
		// b, 完成第一个任务“提交申请”
		String taskId = processEngine.getTaskService().createTaskQuery().processInstanceId(pi.getId()).uniqueResult().getId();// 查询出本流程实例中当前仅有一个任务（提交申请的任务）
		String executionIdSubmit = processEngine.getTaskService().getTask(taskId).getExecutionId();
		processEngine.getTaskService().completeTask(taskId); // 完成任务
		// 发给考勤员
		String content = createContentForSubmit(executionIdSubmit);
		DetachedCriteria dc = this.getCriteria();
		dc.add(Restrictions.eq("superior.id", form.getApplicant().getSuperior().getId()));
		@SuppressWarnings("unchecked")
		List<Tuser> users = hibernateTemplate.findByCriteria(dc);
		// 发给主管
		MailService.sendMail(form.getTitle(), content, users.get(0).getMailBox());
		logger.info("邮件发送主管部门成功!");
		MailService.sendMail(form.getTitle(), content, MailAddress.MONITOR_MAILBOX);
		logger.info("邮件发送monitor成功!");
	}

	/**
	 * @param executionIdSubmit
	 * @return
	 */
	private String createContentForSubmit(String executionIdSubmit) {
		TreeSet<String> names = (TreeSet<String>) processEngine.getExecutionService().getVariableNames(executionIdSubmit);
		String content1 = "";
		String applyName = "";
		String applyName_value = "";
		for (String namesss : names) {
			Object value = processEngine.getExecutionService().getVariable(executionIdSubmit, namesss);
			if (value == null || value.toString().indexOf("@") != -1) {
				continue;
			}
			if (namesss == null || namesss.toString().indexOf("申请人") != -1) {
				applyName = namesss;
				applyName_value = value.toString();
				continue;
			}
			content1 += "<div>";
			content1 += namesss;
			content1 += ":";
			content1 += value;
			content1 += "</div>";
		}
		content1 += "<div>";
		content1 += applyName;
		content1 += ":";
		content1 += applyName_value;
		content1 += "</div>";
		String content = content1;
		return content;
	}

	/**
	 * @param form
	 * @param fields
	 * @param isProxy
	 * @param name
	 * @return
	 */
	private ProcessInstance saveFormAndStartProcess(Tform form, List<FieldPageModel> fields, String isProxy, String name) {
		// 1，设置属性并保存表单
		form.setTitle(form.getFormTemplate().getName() + "_" + form.getApplicant().getName() + "_" + sdf.format(form.getApplyTime())); // 标题的格式为：{模板名称}_{申请人姓名}_{申请时间}
		form.setStatus(Form.STATUS_RUNNING); // 状态为正在审批中

		// 2，开始流转
		// a, 启动流程实例，并设置流程变量
		String processKey = form.getFormTemplate().getProcessDefinitionKey();
		Map<String, Object> variables = new LinkedHashMap<String, Object>(); // 流程变量
		variables.put("form", form);
		for (FieldPageModel fieldPageModel : fields) {
			variables.put(fieldPageModel.getDescription(), fieldPageModel.getValue());
		}
		if (isProxy != null && isProxy.equals("on")) {
			variables.put("代申请人", name);
		}
		ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey(processKey, variables);

		form.setProcessInstanceId(pi.getId());// 设置表单所属的流程实例
		formDao.save(form); // 保存表单
		return pi;
	}

	/**
	 * @return
	 */
	private DetachedCriteria getCriteria() {
		return DetachedCriteria.forClass(Tuser.class);
	}

	@Override
	public List<TaskView> findMyTaskViewList(User user) {
		// 1，获取任务列表
		List<Task> taskList = processEngine.getTaskService().findPersonalTasks(user.getLoginName());

		// 2，获取与当前审批任务对应的待审批的表单，并放到要返回的结果集合中
		List<TaskView> taskViewList = new ArrayList<TaskView>();
		for (Task task : taskList) {
			Tform form = (Tform) processEngine.getTaskService().getVariable(task.getId(), "form");

			TaskView taskView = new TaskView();
			taskView.setTitle(form.getTitle());
			taskView.setFormId(form.getId());
			taskView.setApplyTime(form.getApplyTime());
			taskView.setLoginName(form.getApplicant().getLoginName());
			taskView.setCreateTime(task.getCreateTime());
			taskView.setDuedate(task.getDuedate());
			taskView.setExecutionId(task.getExecutionId());
			taskView.setId(task.getId());
			taskView.setName(form.getApplicant().getName());
			taskViewList.add(taskView);
		}

		return taskViewList;
	}

	@Override
	public Tform getById(Long id) {
		return formDao.get(Tform.class, id);
	}

	@Override
	public void approve(TapproveInfo approveInfo, String taskId, String outcome) throws Exception {
		// 保存审批信息
		approveInfoDao.save(approveInfo);
		// 完成任务
		Task task = processEngine.getTaskService().getTask(taskId);// 这个获取正在执行的任务的代码必须要放在完成任务之前，如果放到后则就查不到了，因为变成历史了
		String startTime = (String) processEngine.getExecutionService().getVariable(processEngine.getTaskService().getTask(taskId).getExecutionId(), LightmvcConstants.STAFF_STARTTIME);
		String endTime = (String) processEngine.getExecutionService().getVariable(processEngine.getTaskService().getTask(taskId).getExecutionId(), LightmvcConstants.STAFF_ENDTIME);
		String executionId = task.getExecutionId();
		StringBuilder content = createContentForApprove(approveInfo, executionId);
		completeTask(taskId, outcome);
		// 获取当前正执行的流程实例对象（如果查到的为null，表示已经执行完了）
		ProcessInstance pi = processEngine.getExecutionService().findProcessInstanceById(executionId);
		// 维护表单状态
		Tform form = approveInfo.getForm();
		if (!approveInfo.isApproval()) {
			// 如果本次未同意，流程直接结束，表单状态为：未通过
			if (pi != null) {
				processEngine.getExecutionService().endProcessInstance(task.getExecutionId(), ProcessInstance.STATE_ENDED);
			}
			form.setStatus(Form.STATUS_REJECTED);
		} else {
			// 如果本次同意，且本次是最后一个审批，就表示所有的环节都通过了，则流程正常结束，表单的状态为：已通过
			if (pi == null) { // 如果本流程实例已执行完，表示本次是最后一个审批
				form.setStatus(Form.STATUS_APPROVED);
				Tuser user = form.getApplicant();
				user.setStatus(Tuser.STATUS_HOLIDAY);
				form.setRegister(approveInfo.getApprover().getName());
				userDao.update(user);
			}
		}
		MailService.sendMail(form.getTitle(), content.toString(), approveInfo.getForm().getApplicant().getMailBox());//发送给申请人
		MailService.sendMail(form.getTitle(), content.toString(), MailAddress.MONITOR_MAILBOX);//发给考勤员
		formDao.update(form);

	}

	/**
	 * @param taskId
	 * @param outcome
	 */
	private void completeTask(String taskId, String outcome) {
		if (outcome == null) {
			processEngine.getTaskService().completeTask(taskId);
		} else {
			processEngine.getTaskService().completeTask(taskId, outcome);
		}
	}

	/**
	 * @param approveInfo
	 * @param executionId
	 * @return
	 */
	private StringBuilder createContentForApprove(TapproveInfo approveInfo, String executionId) {
		Set<String> names = processEngine.getExecutionService().getVariableNames(executionId);
		StringBuilder content = new StringBuilder();
		String applyName = "";
		String applyName_value = "";
		for (String namesss : names) {
			if (namesss.equals("form")) {
				continue;
			}
			Object value = processEngine.getExecutionService().getVariable(executionId, namesss);
			if (value == null || value.toString().indexOf("@") != -1) {
				continue;
			}
			if (namesss == null || namesss.toString().indexOf("申请人") != -1) {
				applyName = namesss;
				applyName_value = value.toString();
				continue;
			}
			content.append("<div>").append(namesss).append(":").append(value).append("</div>");
		}
		content.append("<div>").append(applyName).append(":").append(applyName_value).append("</div>");
		content.append("<div>" + "审批人-" + approveInfo.getApprover().getName() + ": " + (approveInfo.isApproval() ? "同意" : "不同意") +  "</div><div>意见 ：" + approveInfo.getComment() + "</div>");
		return content;
	}

	@Override
	public List<Form> getByUser(Tuser tuser) {
		List<Form> forms = new ArrayList<Form>();
		// formDao.findBySql("from workflow_form wh")userid
		List<Tform> tforms = formDao.find("from Tform tf where tf.applicant.id=" + tuser.getId());
		for (Tform tform : tforms) {
			Form form = new Form();
			form.setApplyTime(tform.getApplyTime());
			form.setId(tform.getId());
			form.setTitle(tform.getTitle());
			form.setLoginName(tform.getApplicant().getLoginName());
			form.setStatus(tform.getStatus());
			forms.add(form);
		}
		return forms;
	}

	@Override
	public Set<String> getOutcomesByTaskId(String taskId) {
		return processEngine.getTaskService().getOutcomes(taskId);
	}

	public List<Tfield> getTfieldsByTaskId(String taskId, String formId) {
		List<Tfield> pageModels = new ArrayList<Tfield>();
		Tform tform = formDao.get(Tform.class, Long.valueOf(formId));
		TformTemplate tformTemplate = formTemplateDao.get(TformTemplate.class, tform.getFormTemplate().getId());
		Task task = processEngine.getTaskService().getTask(taskId);// 这个获取正在执行的任务的代码必须要放在完成任务之前，如果放到后则就查不到了，因为变成历史了
		for (Tfield tfield : tformTemplate.getFields()) {
			Tfield tfi = new Tfield();
			BeanUtils.copyProperties(tfield, tfi);
			String value = (String) processEngine.getExecutionService().getVariable(task.getExecutionId(), tfield.getDescription());
			tfi.setValue(value);
			pageModels.add(tfi);
		}
		return pageModels;
	}

	@Override
	public List<ApproveInfo> getApproveInfosByFormId(String formId) {
		Tform tform = getById(Long.valueOf(formId));
		List<ApproveInfo> approveInfos = new ArrayList<ApproveInfo>();
		Set<TapproveInfo> infos = tform.getApproveInfos();
		for (TapproveInfo tapproveInfo : infos) {
			ApproveInfo approveInfo = new ApproveInfo();
			approveInfo.setApproval(tapproveInfo.isApproval());
			approveInfo.setApproveTime(tapproveInfo.getApproveTime());
			approveInfo.setComment(tapproveInfo.getComment());
			approveInfo.setFormId(approveInfo.getFormId());
			approveInfo.setLoginName(tapproveInfo.getApprover().getLoginName());
			approveInfos.add(approveInfo);
		}
		return approveInfos;
	}

	@Override
	public List<Form> getByUser(Tuser tuser, PageFilter ph) {
		List<Form> forms = new ArrayList<Form>();
		// formDao.findBySql("from workflow_form wh")userid
		Map<String, Object> params = new HashMap<String, Object>();
		String hql = "from Tform t where t.applicant.id=" + tuser.getId();
		List<Tform> tforms = formDao.find(hql + orderHql(ph), params, ph.getPage(), ph.getRows());
		for (Tform tform : tforms) {
			Form form = new Form();
			form.setApplyTime(tform.getApplyTime());
			form.setId(tform.getId());
			form.setTitle(tform.getTitle());
			form.setLoginName(tform.getApplicant().getLoginName());
			form.setName(tform.getApplicant().getName());
			form.setStatus(tform.getStatus());
			forms.add(form);
		}
		return forms;
	}

	@SuppressWarnings("unused")
	private String whereHql(Tuser tuser, Map<String, Object> params) {
		String hql = "";
		if (tuser != null) {
			hql += " where 1=1 ";
			if (tuser.getName() != null) {
				hql += " and t.name like :name";
				params.put("name", "%%" + tuser.getName() + "%%");
			}
		}
		return hql;
	}

	public Long count(Tuser tuser) {
		Map<String, Object> params = new HashMap<String, Object>();
		String hql = "from Tform t where t.applicant.id=" + tuser.getId();
		return this.formDao.count("select count(*) " + hql, params);
	}

}
